//! # 健康检查系统模块
//!
//! 提供组件健康状态监控、检查和报告功能
//!
//! 从 rustcloud-bus 提取的健康检查功能，支持：
//! - 组件健康状态检查
//! - 健康检查结果聚合
//! - 自定义健康检查器
//! - 健康状态报告和告警

use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::Duration;

// 为了向后兼容，创建类型别名
type HealthResult<T> = Result<T, crate::ObservabilityError>;
type ObservabilityResult<T> = Result<T, crate::ObservabilityError>;

/// 健康检查结果
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthCheckResult {
    /// 整体健康状态
    pub status: HealthStatus,
    /// 各组件健康状态
    pub components: HashMap<String, ComponentHealth>,
    /// 检查时间
    pub checked_at: chrono::DateTime<chrono::Utc>,
    /// 检查耗时 (毫秒)
    pub check_duration_ms: u64,
}

/// 健康状态枚举
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum HealthStatus {
    /// 健康
    Healthy,
    /// 警告
    Warning,
    /// 严重
    Critical,
    /// 未知
    Unknown,
}

/// 组件健康信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComponentHealth {
    /// 组件状态
    pub status: HealthStatus,
    /// 状态描述
    pub message: String,
    /// 详细信息
    pub details: HashMap<String, String>,
    /// 检查时间
    pub last_check: chrono::DateTime<chrono::Utc>,
}

/// 健康检查器接口
#[async_trait]
pub trait HealthChecker: Send + Sync {
    /// 执行健康检查
    async fn check_health(&self) -> ComponentHealth;
    
    /// 获取检查器名称
    fn name(&self) -> &str {
        "default_checker"
    }
    
    /// 获取检查超时时间
    fn timeout(&self) -> Duration {
        Duration::from_secs(30)
    }
}

/// 健康检查配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthCheckConfig {
    /// 是否启用健康检查
    pub enabled: bool,
    /// 检查间隔 (秒)
    pub check_interval_secs: u64,
    /// 检查超时 (秒)
    pub check_timeout_secs: u64,
    /// 失败重试次数
    pub retry_attempts: u32,
    /// 不健康阈值
    pub unhealthy_threshold: u32,
    /// 健康阈值
    pub healthy_threshold: u32,
}

impl Default for HealthCheckConfig {
    fn default() -> Self {
        Self {
            enabled: true,
            check_interval_secs: 30,
            check_timeout_secs: 10,
            retry_attempts: 3,
            unhealthy_threshold: 3,
            healthy_threshold: 2,
        }
    }
}

/// 健康检查管理器
pub struct HealthCheckManager {
    config: HealthCheckConfig,
    checkers: HashMap<String, Box<dyn HealthChecker>>,
    component_states: HashMap<String, ComponentHealthState>,
}

/// 组件健康状态跟踪
#[derive(Debug, Clone)]
struct ComponentHealthState {
    status: HealthStatus,
    consecutive_failures: u32,
    consecutive_successes: u32,
    last_check: chrono::DateTime<chrono::Utc>,
    last_healthy: Option<chrono::DateTime<chrono::Utc>>,
}

impl HealthCheckManager {
    /// 创建新的健康检查管理器
    pub fn new(config: HealthCheckConfig) -> Self {
        Self {
            config,
            checkers: HashMap::new(),
            component_states: HashMap::new(),
        }
    }

    /// 注册健康检查器
    pub fn register_checker(&mut self, name: String, checker: Box<dyn HealthChecker>) {
        self.checkers.insert(name.clone(), checker);
        self.component_states.insert(name, ComponentHealthState {
            status: HealthStatus::Unknown,
            consecutive_failures: 0,
            consecutive_successes: 0,
            last_check: chrono::Utc::now(),
            last_healthy: None,
        });
    }

    /// 执行所有健康检查
    pub async fn check_all(&mut self) -> ObservabilityResult<HealthCheckResult> {
        let start_time = std::time::Instant::now();
        let mut components = HashMap::new();
        let mut overall_status = HealthStatus::Healthy;

        // 收集检查器名称以避免借用冲突
        let checker_names: Vec<String> = self.checkers.keys().cloned().collect();

        for name in checker_names {
            // 临时取出检查器进行检查
            let checker_result = {
                if let Some(checker) = self.checkers.get(&name) {
                    let component_health = self.check_component_direct(&name, checker.as_ref()).await;
                    Some(component_health)
                } else {
                    None
                }
            };
            
            if let Some(component_health) = checker_result {
                // 更新整体状态
                match component_health.status {
                    HealthStatus::Critical => overall_status = HealthStatus::Critical,
                    HealthStatus::Warning if overall_status == HealthStatus::Healthy => {
                        overall_status = HealthStatus::Warning;
                    }
                    HealthStatus::Unknown if overall_status != HealthStatus::Critical => {
                        overall_status = HealthStatus::Warning;
                    }
                    _ => {}
                }
                
                components.insert(name.clone(), component_health);
            }
        }

        let check_duration = start_time.elapsed();
        
        Ok(HealthCheckResult {
            status: overall_status,
            components,
            checked_at: chrono::Utc::now(),
            check_duration_ms: check_duration.as_millis() as u64,
        })
    }

    /// 检查单个组件 - 不可变版本
    async fn check_component_direct(&self, name: &str, checker: &dyn HealthChecker) -> ComponentHealth {
        let mut attempts = 0;
        let max_attempts = self.config.retry_attempts + 1;
        let mut last_error = None;

        while attempts < max_attempts {
            attempts += 1;
            
            let check_result = tokio::time::timeout(
                Duration::from_secs(self.config.check_timeout_secs),
                checker.check_health()
            ).await;

            match check_result {
                Ok(health) => {
                    return health;
                }
                Err(timeout_err) => {
                    last_error = Some(format!("健康检查超时: {}", timeout_err));
                    if attempts < max_attempts {
                        tokio::time::sleep(Duration::from_millis(100)).await;
                    }
                }
            }
        }

        // 所有重试都失败，返回错误状态
        let error_msg = last_error.unwrap_or_else(|| "健康检查失败".to_string());
        ComponentHealth {
            status: HealthStatus::Critical,
            message: error_msg,
            details: HashMap::new(),
            last_check: chrono::Utc::now(),
        }
    }

    /// 检查单个组件
    async fn check_component(&mut self, name: &str, checker: &dyn HealthChecker) -> ComponentHealth {
        let mut attempts = 0;
        let max_attempts = self.config.retry_attempts + 1;
        let mut last_error = None;

        while attempts < max_attempts {
            attempts += 1;
            
            let check_result = tokio::time::timeout(
                Duration::from_secs(self.config.check_timeout_secs),
                checker.check_health()
            ).await;

            match check_result {
                Ok(health) => {
                    self.update_component_state(name, &health.status);
                    return health;
                }
                Err(timeout_err) => {
                    last_error = Some(format!("健康检查超时: {}", timeout_err));
                    if attempts < max_attempts {
                        tokio::time::sleep(Duration::from_millis(100)).await;
                    }
                }
            }
        }

        // 所有重试都失败，返回错误状态
        let error_msg = last_error.unwrap_or_else(|| "健康检查失败".to_string());
        let health = ComponentHealth {
            status: HealthStatus::Critical,
            message: error_msg,
            details: HashMap::new(),
            last_check: chrono::Utc::now(),
        };

        self.update_component_state(name, &health.status);
        health
    }

    /// 更新组件状态
    fn update_component_state(&mut self, name: &str, status: &HealthStatus) {
        if let Some(state) = self.component_states.get_mut(name) {
            let now = chrono::Utc::now();
            
            match status {
                HealthStatus::Healthy => {
                    state.consecutive_successes += 1;
                    state.consecutive_failures = 0;
                    state.last_healthy = Some(now);
                    
                    // 连续成功达到阈值，标记为健康
                    if state.consecutive_successes >= self.config.healthy_threshold {
                        state.status = HealthStatus::Healthy;
                    }
                }
                HealthStatus::Critical | HealthStatus::Warning => {
                    state.consecutive_failures += 1;
                    state.consecutive_successes = 0;
                    
                    // 连续失败达到阈值，标记为不健康
                    if state.consecutive_failures >= self.config.unhealthy_threshold {
                        state.status = status.clone();
                    }
                }
                HealthStatus::Unknown => {
                    // 保持当前状态，但重置计数器
                    state.consecutive_failures = 0;
                    state.consecutive_successes = 0;
                }
            }
            
            state.last_check = now;
        }
    }

    /// 获取组件状态
    pub fn get_component_state(&self, name: &str) -> Option<&ComponentHealthState> {
        self.component_states.get(name)
    }

    /// 启动定期健康检查
    pub async fn start_periodic_checks(&mut self) -> ObservabilityResult<()> {
        if !self.config.enabled {
            tracing::info!("健康检查已禁用");
            return Ok(());
        }

        tracing::info!("启动定期健康检查，间隔: {}秒", self.config.check_interval_secs);
        
        // 由于 Rust 所有权限制，这里需要重新设计架构
        // 实际实现中会使用 Arc<Mutex<HealthCheckManager>> 和定时器
        Ok(())
    }
}

/// 数据库健康检查器
pub struct DatabaseHealthChecker {
    name: String,
    connection_string: String,
}

impl DatabaseHealthChecker {
    pub fn new(name: String, connection_string: String) -> Self {
        Self {
            name,
            connection_string,
        }
    }
}

#[async_trait]
impl HealthChecker for DatabaseHealthChecker {
    async fn check_health(&self) -> ComponentHealth {
        // 简化实现 - 实际中会执行数据库连接测试
        let now = chrono::Utc::now();
        
        // 模拟数据库检查
        tokio::time::sleep(Duration::from_millis(10)).await;
        
        ComponentHealth {
            status: HealthStatus::Healthy,
            message: "数据库连接正常".to_string(),
            details: {
                let mut details = HashMap::new();
                details.insert("connection_string".to_string(), self.connection_string.clone());
                details.insert("response_time_ms".to_string(), "10".to_string());
                details
            },
            last_check: now,
        }
    }

    fn name(&self) -> &str {
        &self.name
    }

    fn timeout(&self) -> Duration {
        Duration::from_secs(5)
    }
}

/// HTTP 端点健康检查器
pub struct HttpHealthChecker {
    name: String,
    url: String,
    expected_status: u16,
}

impl HttpHealthChecker {
    pub fn new(name: String, url: String, expected_status: Option<u16>) -> Self {
        Self {
            name,
            url,
            expected_status: expected_status.unwrap_or(200),
        }
    }
}

#[async_trait]
impl HealthChecker for HttpHealthChecker {
    async fn check_health(&self) -> ComponentHealth {
        let now = chrono::Utc::now();
        let start_time = std::time::Instant::now();
        
        // 使用 reqwest 进行 HTTP 检查
        match reqwest::get(&self.url).await {
            Ok(response) => {
                let status_code = response.status().as_u16();
                let response_time = start_time.elapsed();
                
                let (status, message) = if status_code == self.expected_status {
                    (HealthStatus::Healthy, format!("HTTP 检查成功，状态码: {}", status_code))
                } else {
                    (HealthStatus::Warning, format!("HTTP 状态码不匹配，期望: {}, 实际: {}", self.expected_status, status_code))
                };
                
                ComponentHealth {
                    status,
                    message,
                    details: {
                        let mut details = HashMap::new();
                        details.insert("url".to_string(), self.url.clone());
                        details.insert("status_code".to_string(), status_code.to_string());
                        details.insert("response_time_ms".to_string(), response_time.as_millis().to_string());
                        details
                    },
                    last_check: now,
                }
            }
            Err(err) => {
                ComponentHealth {
                    status: HealthStatus::Critical,
                    message: format!("HTTP 检查失败: {}", err),
                    details: {
                        let mut details = HashMap::new();
                        details.insert("url".to_string(), self.url.clone());
                        details.insert("error".to_string(), err.to_string());
                        details
                    },
                    last_check: now,
                }
            }
        }
    }

    fn name(&self) -> &str {
        &self.name
    }

    fn timeout(&self) -> Duration {
        Duration::from_secs(10)
    }
}

/// 内存使用健康检查器
pub struct MemoryHealthChecker {
    name: String,
    max_usage_percent: f64,
}

impl MemoryHealthChecker {
    pub fn new(name: String, max_usage_percent: f64) -> Self {
        Self {
            name,
            max_usage_percent,
        }
    }
}

#[async_trait]
impl HealthChecker for MemoryHealthChecker {
    async fn check_health(&self) -> ComponentHealth {
        let now = chrono::Utc::now();
        
        // 简化实现 - 实际中会获取真实的内存使用情况
        let current_usage = 45.6; // 模拟当前内存使用率
        
        let (status, message) = if current_usage < self.max_usage_percent {
            (HealthStatus::Healthy, format!("内存使用正常: {:.1}%", current_usage))
        } else if current_usage < self.max_usage_percent * 1.2 {
            (HealthStatus::Warning, format!("内存使用偏高: {:.1}%", current_usage))
        } else {
            (HealthStatus::Critical, format!("内存使用过高: {:.1}%", current_usage))
        };
        
        ComponentHealth {
            status,
            message,
            details: {
                let mut details = HashMap::new();
                details.insert("current_usage_percent".to_string(), format!("{:.1}", current_usage));
                details.insert("max_usage_percent".to_string(), format!("{:.1}", self.max_usage_percent));
                details
            },
            last_check: now,
        }
    }

    fn name(&self) -> &str {
        &self.name
    }

    fn timeout(&self) -> Duration {
        Duration::from_secs(1)
    }
}

/// 磁盘空间健康检查器
pub struct DiskSpaceHealthChecker {
    name: String,
    path: String,
    min_free_percent: f64,
}

impl DiskSpaceHealthChecker {
    pub fn new(name: String, path: String, min_free_percent: f64) -> Self {
        Self {
            name,
            path,
            min_free_percent,
        }
    }
}

#[async_trait]
impl HealthChecker for DiskSpaceHealthChecker {
    async fn check_health(&self) -> ComponentHealth {
        let now = chrono::Utc::now();
        
        // 简化实现 - 实际中会获取真实的磁盘使用情况
        let free_percent = 75.3; // 模拟空闲空间百分比
        
        let (status, message) = if free_percent > self.min_free_percent {
            (HealthStatus::Healthy, format!("磁盘空间充足: {:.1}% 可用", free_percent))
        } else if free_percent > self.min_free_percent * 0.5 {
            (HealthStatus::Warning, format!("磁盘空间不足: {:.1}% 可用", free_percent))
        } else {
            (HealthStatus::Critical, format!("磁盘空间严重不足: {:.1}% 可用", free_percent))
        };
        
        ComponentHealth {
            status,
            message,
            details: {
                let mut details = HashMap::new();
                details.insert("path".to_string(), self.path.clone());
                details.insert("free_percent".to_string(), format!("{:.1}", free_percent));
                details.insert("min_free_percent".to_string(), format!("{:.1}", self.min_free_percent));
                details
            },
            last_check: now,
        }
    }

    fn name(&self) -> &str {
        &self.name
    }

    fn timeout(&self) -> Duration {
        Duration::from_secs(2)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_health_check_manager() {
        let config = HealthCheckConfig::default();
        let mut manager = HealthCheckManager::new(config);
        
        // 注册一个模拟检查器
        let checker = Box::new(DatabaseHealthChecker::new(
            "test_db".to_string(),
            "test://localhost:5432".to_string()
        ));
        manager.register_checker("database".to_string(), checker);
        
        // 执行健康检查
        let result = manager.check_all().await.unwrap();
        assert_eq!(result.components.len(), 1);
        assert!(result.components.contains_key("database"));
    }

    #[tokio::test]
    async fn test_database_health_checker() {
        let checker = DatabaseHealthChecker::new(
            "test_db".to_string(),
            "postgresql://localhost:5432/test".to_string()
        );
        
        let health = checker.check_health().await;
        assert_eq!(health.status, HealthStatus::Healthy);
        assert_eq!(checker.name(), "test_db");
    }

    #[tokio::test]
    async fn test_memory_health_checker() {
        let checker = MemoryHealthChecker::new(
            "memory".to_string(),
            80.0
        );
        
        let health = checker.check_health().await;
        // 由于模拟的内存使用率是 45.6%，应该是健康状态
        assert_eq!(health.status, HealthStatus::Healthy);
    }

    #[tokio::test]
    async fn test_disk_space_health_checker() {
        let checker = DiskSpaceHealthChecker::new(
            "disk".to_string(),
            "/".to_string(),
            20.0
        );
        
        let health = checker.check_health().await;
        // 由于模拟的空闲空间是 75.3%，应该是健康状态
        assert_eq!(health.status, HealthStatus::Healthy);
    }

    #[test]
    fn test_health_check_config_default() {
        let config = HealthCheckConfig::default();
        assert!(config.enabled);
        assert_eq!(config.check_interval_secs, 30);
        assert_eq!(config.check_timeout_secs, 10);
        assert_eq!(config.retry_attempts, 3);
    }
}